#include "FileOps.h"
#include <sys/stat.h>

bool FileOps::read(const char* path, BYTE* data, int bytecount){
    HANDLE hFile = CreateFileA(path, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);
    DWORD buffer;
    bool success = ReadFile(hFile, data, bytecount, &buffer, NULL);
    CloseHandle(hFile);
    return success;
}

bool FileOps::write(const char* path, BYTE* data, int bytecount){
    //HANDLE hFile = CreateFileA(path, GENERIC_WRITE, 0, 0, OPEN_ALWAYS, 0, 0);
    std::string parent = getParent(path);
    createDirectory(parent.c_str());
    HANDLE hFile = createFile(path, OPEN_ALWAYS);
    if (hFile != NULL){
        DWORD buffer;
        bool success = WriteFile(hFile, data, bytecount, &buffer, NULL);
        CloseHandle(hFile);
        return success;
    }
    return false;
}

bool FileOps::append(const char* path, BYTE* data, int bytecount){
    HANDLE hFile = createFile(path, OPEN_EXISTING);
    bool success;
    if (hFile != NULL){
        int ol = getFileSize(path);
        BYTE* newdata = new BYTE[ol];
        success = read(path, newdata, bytecount);
        if (success){
            memcpy(newdata+ol, data, bytecount);
            success = write(path, newdata, ol+bytecount);
        }
    }
    else {
        success = write(path, data, bytecount);
    }
    CloseHandle (hFile);
    return success;
}

std::string FileOps::getParent(const char* path){
    std::string s (path);
    int i = s.find_last_of('\\');
    if (i < 0) return "";
    int count = s.length()+1;
    std::string newstring = s.substr(0, count- (count - i));
    return newstring;
}

std::string FileOps::getName(const char* path){
    std::string s (path);
    int i = s.find_last_of('\\');
    if (i < 0) return "";
    int length = s.length();
    std::string newstring = s.substr(i+1, length - i);
    return newstring;
}

HANDLE FileOps::createFile(const char* path, DWORD readType){
    HANDLE rv = CreateFileA(path, GENERIC_WRITE, 0, 0, readType, 0, 0);
    if (rv == INVALID_HANDLE_VALUE){
        rv = NULL;
    }
    return rv;
}

int FileOps::getFileSize(const char* path){
    HANDLE hFile = CreateFileA(path, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);
    if (hFile == INVALID_HANDLE_VALUE){
        return -1;
    }
    CloseHandle(hFile);
    struct stat results;
    stat(path, &results);
    return results.st_size;
}

bool FileOps::createDirectory(const char* path){
    std::string s (path);
    int rv = CreateDirectoryA(path, NULL);
    if (rv != 0) return true;
    DWORD ecode = GetLastError();
    if (ecode == ERROR_ALREADY_EXISTS) return true;
    if (ecode == ERROR_PATH_NOT_FOUND){
        bool success = createDirectory(getParent(path).c_str());
        if (success){
            success = createDirectory(path);
        }
        return success;
    }
	return false;
}

char* FileOps::getTimestamp(){
    SYSTEMTIME t;
    GetSystemTime(&t);
    std::string s = "";
    s.append(integerToString((int)t.wYear, 10));
    s = s + "-";
    s.append(integerToString((int)t.wMonth, 10));
    s = s + "-";
    s.append(integerToString((int)t.wDay, 10));
    s = s + "-";
    s.append(integerToString((int)t.wHour, 10));
    s = s + "-";
    s.append(integerToString((int)t.wMinute, 10));
    s = s + "-";
    s.append(integerToString((int)t.wSecond, 10));
    char* rv = new char[s.length()+1];
    memcpy(rv, s.c_str(), s.length()+1);
    return rv;
}

char* FileOps::integerToString(int integer, int base){
    char buffer[33];
    itoa(integer, buffer, base);
    int length = 0;
    for (int i = 1; i < 33; i++){
        if (buffer[i]=='\0'){
            length = i + 1;
            break;
        }
        else i++;
    }
    char* rv = new char[length];
    memcpy(rv, buffer, length);
    return rv;
}

char* FileOps::longToString(long lvar, int base){
        char buffer[65];
    itoa(lvar, buffer, base);
    int length = 0;
    for (int i = 1; i < 33; i++){
        if (buffer[i]=='\0'){
            length = i + 1;
            break;
        }
        else i++;
    }
    char* rv = new char[length];
    memcpy(rv, buffer, length);
    return rv;
}
int FileOps::stringToInteger(char* string){
    return atoi(string);
}

char* FileOps::getFileTree(char* folder, int* length){
    std::string treestring = "";
    std::string s (folder);
    s.append("\\*");
    WIN32_FIND_DATAA info;
    HANDLE search = FindFirstFileA(s.c_str(), &info);
    if (search != INVALID_HANDLE_VALUE){
        while(FindNextFileA(search, &info)){
            treestring.append(info.cFileName);
            treestring.append("|");
        }
        FindClose(search);
        int al = treestring.length();
        char* tree = new char[al];
        const char* tempstring = treestring.c_str();
        memcpy(tree, tempstring, al+1);
        *length = al+1;
        return tree;
    }
    return NULL;
}

bool FileOps::exists(const char* path){
	HANDLE h = createFile(path, OPEN_EXISTING);
	if (h == NULL) return false;
	else {
		CloseHandle(h);
		return true;
	}
}

double FileOps::stringToDouble(char* string){
	return atof(string);
}

bool FileOps::deleteFile(const char* path){
	return DeleteFileA(path);
}